package bookworm;

import java.util.LinkedList;

public class FiltersReviewsByTag 
{
	/**
	 * filters reviews(passed as parameter) to return only the reviews which have at least
	 * one tag from the list of tags(also passed as parameter) 
	 * @param tags the tags to filter reviews(review must have at least one tag from this list to be passed as result).
	 * @param allReviews all the reviews to be filtered
	 * @return only reviews which have at least one tag from the list of tags.
	 */
	public static LinkedList<Review> filterReviewsByTags(LinkedList<String> tags, LinkedList<Review> allReviews)
	{
		LinkedList<Review> reviewsWithTagsSpecified = new LinkedList<Review>();
		for(int i = 0; i < tags.size(); i++)
		{
			String singleTag = tags.get(i);
			for(int j = 0; j < allReviews.size(); j++)
			{
				Review singleReview = allReviews.get(j);
				if(singleReview.doesReviewHaveThisTag(singleTag) == true)
				{
					if(reviewsWithTagsSpecified.contains(singleReview) != true)
					{
						//review was not already added.
						reviewsWithTagsSpecified.add(singleReview);
					}
				}
			}
		}
		
		return reviewsWithTagsSpecified;
	}
	
	public static LinkedList<String> getTagsOfReviewsByMostAppearanceOrder(LinkedList<Review> reviews)
	{
		LinkedList<String> tagsAppeared = new LinkedList<String>();
		LinkedList<Integer> howManyTimesTagsAppeared = new LinkedList<Integer>();
		
		for(int i = 0; i < reviews.size(); i++)
		{
			Review singleReview = reviews.get(i);
			/*
			 * first, let's add in tagsAppeared the new tags which are in this single Review and
			 * have not yet appeared in any previous review(meaning the tag isn't already in tagsAppeared)
			 */
			LinkedList<String> newTagsFoundOnReview = 
					getTagsInReviewThatAreNotInList(singleReview, tagsAppeared);
			//let's add these new tags in tagsAppeared
			for(int j = 0; j < newTagsFoundOnReview.size(); j++)
			{
				String newTagFound = newTagsFoundOnReview.get(j);
				tagsAppeared.add(newTagFound);
				howManyTimesTagsAppeared.add(0);
			}
			//now let's increase the counters in howManyTimesTagsAppeared according to the tags that appeared in review
			for(int k = 0; k < tagsAppeared.size(); k++)
			{
				String singleTagThatApprearedInSomeReview = tagsAppeared.get(k);
				if(singleReview.doesReviewHaveThisTag(singleTagThatApprearedInSomeReview) == true)
				{
					int howManyTimesSingleTagAppreared = howManyTimesTagsAppeared.get(k);
					howManyTimesSingleTagAppreared = howManyTimesSingleTagAppreared + 1;
					howManyTimesTagsAppeared.set(k, howManyTimesSingleTagAppreared);
				}
			}
			
		}
		
		//finally, let's get the tags of reviews by most appearance order!
		LinkedList<String> tagsOfReviewsByMostAppearanceOrder =
				orderTagsByAppearance(tagsAppeared, howManyTimesTagsAppeared);
		return tagsOfReviewsByMostAppearanceOrder;
		
	}
	
	/**
	 * given a review and a list of tags, it returns tags which are in review 
	 * yet aren't in the list of tags
	 * @param review the reviews which we must extract the tags that aren't in the list
	 * @param tagsInList the list of tags which doesn't contain the tags in result
	 * @return tags tags which are in review yet aren't in the list of tags
	 */
	private static LinkedList<String> getTagsInReviewThatAreNotInList(Review review, LinkedList<String> tagsInList)
	{
		LinkedList<String> tagsInReviewThatAreNotInList = new LinkedList<String>();
		
		LinkedList<String> tagsOfReview = review.getTags();
		for(int i = 0; i < tagsOfReview.size(); i++)
		{
			String singleTagOfReview = tagsOfReview.get(i);
			
			boolean tagFoundOnList = false;
			for(int j = 0; j < tagsInList.size(); j++)
			{
				String singleTagInList = tagsInList.get(j);
				if(singleTagOfReview.compareToIgnoreCase(singleTagInList) == 0)
				{
					tagFoundOnList = true;
					break;
				}
			}
			
			if(tagFoundOnList == false)
			{
				tagsInReviewThatAreNotInList.add(singleTagOfReview);
			}
		}
		
		return tagsInReviewThatAreNotInList;
	}
	
	private static LinkedList<String> orderTagsByAppearance(LinkedList<String> tags, LinkedList<Integer> howManyTimesTagAppeared)
	{
		//let's order tags using bubble sort
		int i, j;
		for(i = 0; i < howManyTimesTagAppeared.size() - 1; i++)
		{
			for(j = 0; j < howManyTimesTagAppeared.size() - 1 - i; j++)
			{
				int elementToCompare = howManyTimesTagAppeared.get(j);
				int elementToCompareSuccessor = howManyTimesTagAppeared.get(j + 1);
				if(elementToCompare < elementToCompareSuccessor)
				{
					//elementToCompare has a bigger value than it's successor. Let's swap them.
					int swapHelper = elementToCompare;
					howManyTimesTagAppeared.set(j, elementToCompareSuccessor);/*the successor will now be the predecessor*/
					howManyTimesTagAppeared.set(j + 1, swapHelper);
					
					/*
					 * let's also swap the tags in the LinkedList which correspond to the successor and predecessor
					 */
					
					String tagPredecessor = tags.get(j);
					String tagSuccessor = tags.get(j + 1);
					String tagSwapHelper = tagPredecessor;
					tags.set(j, tagSuccessor);
					tags.set(j + 1, tagSwapHelper);
				}
			}
		}
		
		return tags;
	}

}
